﻿#include<stdio.h>
#include<iostream>
//类的定义
//类似于C的结构体，不同的是，C++的类既可以定义变量，也可以定义函数
//类的定义关键字可以是struct也可以是class
using namespace std;
class lei {
public:
	void print() {
		cout << "print" << endl;
	}
	//成员函数
private:
	int a;
	char b;
	//成员变量或属性
};
//类里面的函数默认是调用inline的
class Data {
public:
	void Init(int year, int month, int day) {
		_year = year;
		_month = month;
		_day = day;
	}
	void Print() {
		cout << _year << _month << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
	//在定义变量时，一般加上特殊标记，防止初始化时赋值混乱
};
//关于public和private,这是类里面的两个限定符，
//public修饰的成员类内类外都可以访问，而private在类外不能访问
//而struct和class修饰的类在默认限定上（即不加public和private修饰的成员）也有区别
//struct修饰：默认公有（public）
//class修饰：默认私有（private)


/*类域*/
//类定义的作用域称为类域，由于不同类中的成员可以同名，因此引用有关类域中的成员需要指定类域名称
class DataA {
public:
	void Init(int year = 24, int month = 8, int day = 9);
	void Print();
private:
	int _year;
	int _month;
	int _day;
};
//当声明在类中，定义在类外时，定义方法需要指定类域“DataA::Init”
void DataA::Init(int year, int month, int day) {
	_year = year;
	_month = month;
	_day = day;
	//即使类中的属性私有，也可以直接使用
}
void DataA::Print() {
	cout << _year << _month << _day;
}
/*类的实例化*/
//类的实例化是指将类类型实例化为物理内存中储存的对象的过程称为实例化
//类中的成员只是声明，没有被分配内存
//int main() {
//	DataA A;//为对象A分配对象
//	A.Init();
//	//为对象A赋值
//	A.Print();
//	return 0;
//}
//对象的大小
//类实例化后被赋予存储空间，自然有大小
//类实例化后的大小是类中成员变量的大小，而成员函数是储存在一个公共空间的
//类实例化后的对象的储存符合对其规则，如下：
/*第⼀个成员在与结构体偏移量为0的地址处。
• 其他成员变量要对⻬到某个数字（对⻬数）的整数倍的地址处。
• 注意：对⻬数 = 编译器默认的⼀个对⻬数 与 该成员⼤⼩的较⼩值。
• VS中默认的对⻬数为8
• 结构体总⼤⼩为：最⼤对⻬数（所有变量类型最⼤者与默认对⻬参数取最⼩）的整数倍。
• 如果嵌套了结构体的情况，嵌套的结构体对⻬到⾃⼰的最⼤对⻬数的整数倍处，结构体的整体⼤⼩
就是所有最⼤对⻬数（含嵌套结构体的对⻬数）的整数倍*/
class A {
public:
	void print() {
		cout << "A-Print" << endl;
	}
private:
	int a;
	char b;
};
class B {
public:
	void print() {
		cout << "B-Print" << endl;
	}
};
class C {
	void print() {

	}
};
void test1() {
	cout << "A:" << sizeof(A) << "B:" << sizeof(B) << "C:" << sizeof(C)<<endl;
}
//A:8B:1C:1
//根据对其规则，A中只计算了成员变量，上⾯的程序运⾏后，我们看到没有成员变量的B和C类对象的⼤⼩是1，为什么没有成员变量还要给1个
//字节呢？因为如果⼀个字节都不给，怎么表⽰对象存在过呢！所以这⾥给1字节，纯粹是为了占位标识
//对象存在。


//this指针
void test02(){
	Data D1;
	Data D2;
	D1.Init(24, 1, 1);
	D2.Init(23, 2, 2);
	D1.Print();
	D2.Print();
	//上面我们说过成员函数存在于一个公共空间中，即D1和D2调用的是同一个函数，
	// 那为什么编译器能够区分我们所传的参数是传给D1空间的还是D2空间的呢？
	//因为this指针，在类中创建函数时，会自动给一个形参this指针（隐藏的，不能自己再重复给），
	// void Init(Date* const this, int year, int month, int day)
	//这个this指针传递的是D1或D2的地址，即D1,D2调用函数时会把自己的地址自动传给this指针
	// d1.Init(&d1, 2024, 3, 31);
	//this指针的作用就是辅助成员函数的调用，它可以再成员函数内调用，但不能更改
	// this = nullptr;×
	// 编译报错：error C2106: “=”: 左操作数必须为左值
	// this->_year = year;✔
}
int main() {
	test02();
	return 0;
}